package com.example.xjt.restful;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("公共返回体")
public class ResultVO<T> {
    @ApiModelProperty("系统返回码")
    private int code;  //这里是本系统的API返回码，而不是HTTP协议的状态码，只要HTTP_STATUS=200，都表示服务器处理了客户端的请求
                       //而resultCode是和前端约定 请求后端成功后，返回数据的业务状态，所以resultCode是程序员定义的
    @ApiModelProperty("系统返回码描述信息")
    private String msg;
    @ApiModelProperty("系统返回的数据")
    private T data;
    @ApiModelProperty("系统响应时间戳")
    private Long timestamp;
    @ApiModelProperty("语言")
    private String lang;   // GlobalExceptionHandler中会动态处理lang

    /**
     * 请求是否处理成功
     * <p>
     * 只有resultCode为0时，请求处理成功，其他情况均为处理失败;
     * success=true时，code一定为0；
     * success=false时,code不一定为0,此时会根据异常枚举返回对应的异常信息
     * <p>
     * 有的前端开发者 会根据code判断api的多种返回情况；
     * 而有的前端开发 则要求-只根据success判断 成功/失败 这2种api处理情况，根据你同事的实际情况来
     */
    @ApiModelProperty("请求是否处理成功")
    private boolean success;


    public ResultVO(int code, String msg, boolean success) {
        this.code = code;
        this.msg = msg;
        this.data = null;
        this.timestamp = System.currentTimeMillis();
        this.success = success;
    }

    public ResultVO(int code, String msg, T data, boolean success) {
        this.code = code;
        this.msg = msg;
        this.data = data;
        this.timestamp = System.currentTimeMillis();
        this.success = success;
    }

    public ResultVO(int code, String msg, T data, Long timestamp, boolean success) {
        this.code = code;
        this.msg = msg;
        this.data = data;
        this.timestamp = timestamp;
        this.success = success;
    }

    public ResultVO(ResultCodeEnum resultCode, T data, boolean success) {
        this(resultCode.getCode(),resultCode.getMsg(),data,System.currentTimeMillis(),success);
    }

    public ResultVO(ResultCodeEngEnum resultCode, T data, boolean success) {
        this(resultCode.getCode(),resultCode.getMessage(),data,System.currentTimeMillis(),success);
    }

    //---------------请求处理成功的情况，使用success固定枚举，data可有可无--------------------------------------------------

    //处理成功，有返回数据的情况
    public static ResultVO ok(Object data) {
        return new ResultVO(ResultCodeEnum.SUCCESS, data, true);
    }

    //处理成功,没有返回数据的情况
    public static ResultVO ok() {
        return new ResultVO(ResultCodeEnum.SUCCESS, null, true);
    }


    //----------------------------------请求处理失败的情况，强制使用枚举定义的ERROR---------------------------------------

    //业务失败，返回预定的code和msg
    //若代码里不想使用 throw new ApiExp(XXX)方式处理异常，
    //则可以用 ResultVO.fail(XXX) 抛出定义的枚举异常，适用于明确知道 双分支/多分支的错误情况返回
    //例如 多种情况对应多种错误的时候，可以每种错误都throw，也可以每种错误都 return fail，按程序员的编程习惯来
    //ps:
    //   if(xxxx){
    //      ResultVO.fail(XXX)
    //    }
    //    else if(xxxx){
    //       ResultVO.fail(XXX)
    //    }

    //处理失败-无返回数据
    public static ResultVO fail(ResultCodeEnum resultCode) {
        return new ResultVO(resultCode.getCode(), resultCode.getMsg(), false);
    }

    //处理失败-有返回数据
    public static ResultVO fail(ResultCodeEnum resultCode, Object data) {
        return new ResultVO(resultCode.getCode(), resultCode.getMsg(), data, false);
    }

    //受检异常，throw ApiExp返回自定义的code/msg
    public static ResultVO exception(int code, String msg) {
        return new ResultVO(code, msg, false);
    }

    //受检异常，返回预定的resultCode和异常msg信息
    public static ResultVO exception(ResultCodeEnum resultCode, Exception ex) {
        return new ResultVO(resultCode, ex.getMessage(), false);
    }


    //受检异常，返回预定的resultCode和异常数据
    public static ResultVO exception(ResultCodeEnum resultCode, Object data) {
        return new ResultVO(resultCode, data, false);
    }

    //受检异常，返回预定的 英文resultCode和异常msg信息
    public static ResultVO exceptionEng(ResultCodeEngEnum resultCode, Exception ex) {
        return new ResultVO(resultCode, ex.getMessage(), false);
    }

    //受检异常，返回预定的 英文 resultCode和异常数据
    public static ResultVO exceptionEng(ResultCodeEngEnum resultCode, Object data) {
        return new ResultVO(resultCode, data, false);
    }


}